﻿using System;
using System.Net;
using System.Linq;
using System.ServiceModel;
using Client.FlightsSearchService;

namespace Client
{
    internal class CommandExecuter
    {
        private const string COMMAND_SEARCH = "search";
        private const string COMMAND_RESERVE = "reserve";
        private const string COMMAND_CANCEL = "cancel";
        private const string COMMAND_EXIT = "exit";

        private readonly IFlightSearchService service;

        internal CommandExecuter(IFlightSearchService service)
        {
            this.service = service;
        }

        public void ExecuteUserCommands()
        {
            Console.Write("> ");
            string line;
            while ((line = Console.ReadLine()) != null && line != COMMAND_EXIT)
            {
                try
                {
                    var args = line.Split(' ');
                    if (args.Length > 0)
                    {
                        var command = args[0];

                        if (command == COMMAND_SEARCH && args.Length == 4)
                        {
                            Search(args[1], args[2], args[3]);
                        }
                        else if (command == COMMAND_RESERVE && args.Length == 4)
                        {
                            Reserve(args[1], args[2], args[3]);
                        }
                        else if (command == COMMAND_CANCEL && args.Length == 3)
                        {
                            Cancel(args[1], args[2]);
                        }
                        else
                        {
                            Console.WriteLine("Unknown command or invalid number of arguments");
                        }
                    }
                }
                catch (CommunicationException e)
                {
                    var exception = e.InnerException as WebException;
                    if (exception != null && exception.Response != null)
                    {
                        var resp = (HttpWebResponse) exception.Response;
                        Console.WriteLine("Failed, {0}", resp.StatusDescription);
                    }
                    else if (e is EndpointNotFoundException)
                    {
                        Console.WriteLine("Failed, server is down");
                    }
                    else
                    {
                        Console.WriteLine("Failed, {0}", e.Message);
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine("Failed to communicate with service: {0}", e.Message);
                }

                Console.Write("> ");
            }
        }

        private void Search(string from, string to, string date)
        {
            var response = service.Search(from, to, date);
            if (response != null && response.Length > 0)
            {
                var results = response.ToList();
                results.Sort((x, y) =>
                {
                    int delta = x.Price.CompareTo(y.Price);
                    if (delta == 0)
                    {
                        delta = y.AvailableSeats.CompareTo(x.AvailableSeats);
                        if (delta == 0)
                        {
                            delta = String.CompareOrdinal(x.FlightId, y.FlightId);
                        }
                    }

                    return delta;
                });

                foreach (var fi in results)
                {
                    Console.WriteLine("{0} {1} {2} seats {3}$",
                        fi.Seller, fi.FlightId, fi.AvailableSeats, fi.Price);
                }
            }
        }

        private void Reserve(string seller, string flightId, string date)
        {
            var reservationInfo = new ReservationInfo
            {
                FlightId = flightId,
                Date = date,
            };

            var result = service.Reserve(seller, reservationInfo);
            Console.WriteLine("OK, reservation ID: {0}", result);
        }

        private void Cancel(string seller, string reservationId)
        {
            service.Cancel(seller, reservationId);
            Console.WriteLine("OK");
        }
    }
}
